#include "SudokuSolver.h"
#include "SudokuNakedSingles.h"
#include "SudokuHiddenSingles.h"
#include "SudokuLockedCandidatesPointing.h"
#include "SudokuLockedCandidatesClaiming.h"
#include "SudokuNakedSubsets.h"
#include "SudokuHiddenSubsets.h"
#include "SudokuFish.h"

SudokuSolver::SudokuSolver(QObject* parent) : QObject(parent)
{
    addTechnique(new SudokuNakedSingles(this));
    addTechnique(new SudokuHiddenSingles(this));
    addTechnique(new SudokuLockedCandidatesPointing(this));
    addTechnique(new SudokuLockedCandidatesClaiming(this));
    addTechnique(new SudokuNakedSubsets(this));
    addTechnique(new SudokuHiddenSubsets(this));
    addTechnique(new SudokuFish("XWing", Xwing, 2, this));
    addTechnique(new SudokuFish("Swordfish", Swordfish , 3, this));
    addTechnique(new SudokuFish("Jellyfish", Jellyfish, 4, this));
}

SudokuSolver::~SudokuSolver()
{
    qDebug() << "SudokuSolver::~SudokuSolver" << this;
}

void SudokuSolver::solve(SudokuData* sudokuData, int solveMask, bool resetResults)
{
    bool solveProgress;

    //TODO run naked singles after every single method? will be more efficient?
    //on candidate eliminated try to fill cell and eliminet further?

    if(resetResults)
    {
        mTechniqueCountMap.clear();
    }

    // Set sudoku data for all techniques
    foreach(SudokuAbstractSolvingTechnique* technique, mTechniqueMap)
    {
        technique->setSudokuData(sudokuData);
    }

    do
    {
        solveProgress = false;
        foreach(SudokuAbstractSolvingTechnique* technique, mTechniqueMap)
        {
            if(technique->getType() & solveMask)
            {
                int solveResult = 0;
                do
                {
                    technique->run();
                    //technique->start();
                    //technique->wait();
                    solveResult = technique->getCount();
                    mTechniqueCountMap[technique->getType()] += solveResult;
                    if(solveResult > 0)
                        solveProgress = true;
                }
                while(solveResult > 0);
            }
        }
    }while(solveProgress);

    qDebug() << "SudokuSolver::solve mTechniqueCountMap=" << mTechniqueCountMap;
}

void SudokuSolver::addTechnique(SudokuAbstractSolvingTechnique* technique)
{
    mTechniqueMap.insert(technique->getType(), technique);
}
